// vue插件编写
// 保存一下Vue实例，方便在VueRouter类中使用
let Vue;


class VueRouter {
    constructor(options) {
        // 将实例化的选项内容保存
        this.$options = options;

        // 因为current并非响应式，所以导致我们的路由变化并没有改变页面组件，所以我们放弃这种声明方式
        // this.current = "/";

        /**
         * 错误的声明响应式有几种方法
         * Vue.set(this, "current", "/");  这种不行，因为这个需要this也是响应式的才可以
         * Object.defineProperty(); 这种也不行，因为这个是进行拦截，并没有建立关系，所以即使拦截下来，我们没有关系对应也是没有意义
         * 可行的声明响应式变量
         * new Vue();  我们借助new Vue声明响应式数据，这个方法主要是复杂
         * Vue.util.defineReactive(this, "current", "/") 这个方法是一个隐藏api，可以为非响应式对象声明响应式属性
         */
        Vue.util.defineReactive(this, "current", window.location.hash.slice(1) || "/")
        window.addEventListener("hashchange", () => {
            this.current = window.location.hash.slice(1);
        })
    }
}


/**
 * 实现install方法：Vue.use => 执行install方法
 * 注册router-link组件
 * 注册router-view组件
 * @param Vue - Vue构造函数
 */
VueRouter.install = function (_Vue) {
    Vue = _Vue;

    Vue.mixin({
        beforeCreate() {
            // 如果存在router属性，说明是在进行new Vue操作，这个时候将router对象放入Vue实例中
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })


    /**
     * <router-link class="link-item" to="/">首页</router-link>
     * 这个组件我们应该渲染成为一个a标签，作为跳转使用
     * 这里我们主要获取两样东西
     *     文案： 首页
     *     跳转链接地址：to属性
     *
     * 这属于一个组件，所以应该有组件相关内容
     * 文案可以通过插槽获取，这个内容属于默认插槽内容，所以我们直接可以使用this.$slots.default获取
     * 跳转链接地址属于组件的属性，所以我们可以使用props获取
     */
    Vue.component("router-link", {
        props: {
            to: {
                type: String,
                required: true
            }
        },
        // 这里只能是使用render函数的形式注册组件，因为这里的Vue是运行时版本的，并不支持模板解析功能
        render(h) {
            return h("a", {
                attrs: {
                    href: "#" + this.to
                }
            }, this.$slots.default);
        }
    });

    /**
     * <router-view />
     * 这个组件其实就是渲染对应的页面组件即可，所以这个组件基本不需要获取什么东西
     * 我们要根据的是路由的地址在我们配置的路由文件“./index.js”中找到对应的组件，然后进行渲染
     * window.location.hash中就能找到我们想要的路由信息
     * 我们想要的routes其实在我们的main.js中有被放在new Vue的选项中，但是我们使用Vue.use方法原早于new Vue
     * 所以这里的Vue实例是没有我们想要的routes的，我们又该如何获取到呢？
     * 答：我们在注册组件前还需要做一步，在组件实例化前，通过混入的形式，将router挂载到Vue实例的$router属性上
     * 我们就能保证我们使用this.$router获取到VueRouter实例
     *     this.$router.$options.routes   路由映射
     *     this.$router.current           当前路由地址
     * 当我们完成这一步的时候，我们发现我们页面第一次能正确渲染了，但是切换路由的时候页面并没有改变？
     * 答：我们的this.$router.current并非响应式，所以我们改变了值，并没有触发router-view的刷新
     *
     * 我们需要将this.$router.current变为响应式
     */
    Vue.component("router-view", {
        render(h) {
            let currentRoute = this.$router.$options.routes.find(item => item.path === this.$router.current);
            let currentComponent = null;
            if (currentRoute) {
                currentComponent = currentRoute.component;
            }
            return h(currentComponent);
        }
    });
}

export default VueRouter;
